package com.repro.lib_base.liveData

import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import java.lang.Exception
import java.util.*
import java.util.concurrent.atomic.AtomicInteger
import kotlin.collections.HashMap

open class ProtectedSingleLiveData<T> : LiveData<T>() {
    //创建一个初代版本号
    private val START_VERSION = -1

    //创建一个原子类的数据类型
    var mCurrentVersion = AtomicInteger(START_VERSION)

    var isAllowNullValue: Boolean = false


    private var myObserverWrapperMap: HashMap<Observer<in T>, ObserverWrapper<in T>> = HashMap()

    override fun setValue(value: T) {
        mCurrentVersion.getAndIncrement()
        super.setValue(value)
    }

    /**
     * 使用hook反射技术修改mLastVersion值使其等于liveData中mVersion值这样不会触发粘性事件，先setValue,后observe的做法已经行不通了，这就是所谓的非粘性
     * 创建观察者 observe执行顺序必须在setValue之前 并且如果observer为执行完毕的时候执行setValue会有丢失数据风险，虽然概率比较低
     * 可以有效防止数据倒灌产生
     */
    override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
        super.observe(owner, createObserverWrapper(observer, mCurrentVersion.get()))
//        try {
//            //使用hook更改version之后会会导致setValue 在observer之前的数据会失效 必须严格执行先注册在发送数据
//            HookLiveDataVersionUtils.hook(observer)
//        } catch (e: Exception) {
//            e.printStackTrace()
//        }
    }

    /**
     * 带不关联生命周期的观察着
     */
    override fun observeForever(observer: Observer<in T>) {
        super.observeForever(createObserverForeverWrapper(observer, mCurrentVersion.get()))
    }

    /**
     * 粘性事件，并且会出现数据倒灌的情况，数据倒灌是指observer在setValue之后触发，并且一次setValue能够多次触发之前数据observer
     * 导致数据出现程序逻辑混乱情况
     */
    public fun observerSticky(owner: LifecycleOwner, observer: Observer<in T>) {
        super.observe(owner, createObserverWrapper(observer, START_VERSION, true))
    }

    /**
     * 带粘性的不关联生命周期的观察者注册事件 同observerSticky 会发生数据倒灌情况
     */
    public fun observerStickyForever(observer: Observer<in T>) {
        super.observeForever(createObserverForeverWrapper(observer, START_VERSION, true))
    }

    /**
     * 移除非生命周期感知取消注册监听
     */
    override fun removeObserver(observer: Observer<in T>) {
        if (observer.javaClass.isAssignableFrom(ObserverWrapper::class.java)) {
            super.removeObserver(observer)
        } else {
            super.removeObserver(createObserverWrapper(observer, START_VERSION))
        }
    }


    private fun createObserverForeverWrapper(
        observer: Observer<in T>,
        mVersion: Int,
        isStickyEvent: Boolean = false
    ): ObserverWrapper<T> {
        return ObserverWrapper(observer, mVersion, true, isStickyEvent)
    }

    private fun createObserverWrapper(
        observer: Observer<in T>,
        mVersion: Int,
        isStickyEvent: Boolean = false
    ): ObserverWrapper<T> {
        return ObserverWrapper(observer, mVersion, isStickyEvent)
    }

    /**
     * 手动将消息从内存中清楚
     * 避免长期存储在内存发生溢出
     */
    public fun clear() {
        super.setValue(null)
    }

    inner class ObserverWrapper<T> : Observer<T> {
        private var mObserver: Observer<in T>
        private var mVersion: Int = START_VERSION
        private var mIsForever: Boolean = false
        private var isStickyEvent = false
        private var lastObserver: Observer<in T>? = null
        private var lastTime = 0L

        constructor(
            mObserver: Observer<in T>,
            mVersion: Int,
            mIsForever: Boolean,
            isStickyEvent: Boolean = false
        ) {
            this.mObserver = mObserver
            this.mVersion = mVersion
            this.mIsForever = mIsForever
            this.isStickyEvent = isStickyEvent
        }

        constructor(mObserver: Observer<in T>, mVersion: Int, isStickyEvent: Boolean = false) {
            this.mObserver = mObserver
            this.mVersion = mVersion
            this.isStickyEvent = isStickyEvent
        }


        override fun onChanged(t: T) {
            //防止数据回流的核心就是判断一个版本号如果mVersion小于mCurrentVersion则
            //这里判断mCurrentVersion.get()==0主要作用就是判别是否首次进入消息
            /**
             * 首次没有设置observer的时候先设置value 在设置observer 会导致第一次并不会触发onChanged
             *  执行顺序为，setValue --> observer --> onChanged() 会导致第一次不触发 也就是粘性事件并未产生 之后每次触发一次
             *  如果是observer -->setValue -->onChanged() 如果执行时间比较短即注册马上发送事件会导致粘性事件这是处理办法延迟setValue 10mm  这种情况也比较少
             *
             * 设置observerSticky的时候
             *  执行顺序为，setValue --> observer --> onChanged() 首次会触发，但是之后每次会触发两次
             *
             *
             */
            if ((mCurrentVersion.get() > mVersion) && (t != null || isAllowNullValue)) {
                mObserver.onChanged(t)
            }
        }

        override fun equals(o: Any?): Boolean {
            if (this === o) {
                return true
            }
            if (o == null || javaClass != o.javaClass) {
                return false
            }
            val that = o as ObserverWrapper<*>
            return Objects.equals(mObserver, that.mObserver)
        }

        override fun hashCode(): Int {
            return Objects.hash(mObserver)
        }

        override fun toString(): String {
            return super.toString()
        }

    }
}